/*
 * Copyright 2011 www.pretty-tools.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include "stdafx.h"
#include "NavigatorSupervisor.h"
#include "IE/HtmlEvent.h"
#include "../XPCOMAdapter/XPCOMAdapter_i.h"
#include "RulesUpdateManager.h"
#include "CheckForUpdateThread.h"

#define DAY	(1 * 60 * 60 * 24)

// CNavigatorSupervisor

CNavigatorSupervisor::CNavigatorSupervisor()
    : m_dwCookie(0)
{
}

void CNavigatorSupervisor::UnsetSite()
{
	try
	{
		if (m_browser && m_dwCookie)
			AtlUnadvise(m_browser, DIID_DWebBrowserEvents2, m_dwCookie), m_dwCookie = 0;

        m_browser.Release();
	}
	catch(...)
	{
		ATLTRACE("EXCEPTION on UnsetSite!\n");
        ATLASSERT(FALSE);
	}
}

// IObjectWithSite
STDMETHODIMP CNavigatorSupervisor::SetSite(IUnknown* pUnkSite)
{
	UnsetSite();

	ATLTRACE("SetSite(...)\n");

    if(FAILED(__super::SetSite(pUnkSite)))
		return E_FAIL;

	if (!pUnkSite)
		return S_OK;	

	try
	{
		CComPtr<IOleCommandTarget> cmdTarget;
		if (FAILED(pUnkSite->QueryInterface(&cmdTarget)) || !cmdTarget)
			return E_FAIL;

		CComPtr<IServiceProvider> provider;
		if (FAILED(cmdTarget->QueryInterface(&provider)) || !provider)
			return E_FAIL;

		if (FAILED(provider->QueryService(SID_SWebBrowserApp, IID_IWebBrowser2, (LPVOID*)&m_browser)) || !m_browser)
			return E_FAIL;

		ATLASSERT(m_browser);

		if (FAILED(AtlAdvise(m_browser, GetUnknown(), DIID_DWebBrowserEvents2, &m_dwCookie)))
			m_dwCookie = 0;

	    TCHAR szPath[MAX_PATH+1];
	    ZeroMemory(szPath, sizeof(szPath));
	    if (GetModuleFileName(ModuleHelper::GetModuleInstance(), szPath, MAX_PATH))
            m_strResPath = (CString) _T("res://") + szPath;

		ATLTRACE("SetSite is done\n");
	}
	catch(...)
	{
		ATLTRACE("EXCEPTION on SetSite!\n");
        ATLASSERT(FALSE);
    	return E_FAIL;
	}

    return S_OK;
}

void CNavigatorSupervisor::CheckForUpdate()
{
	// Updating version
	if (!m_cfg.CheckForUpdateInterval)
		return;

	__time64_t current_time = 0;
	_time64(&current_time);

	if (current_time < m_cfg.LastCheckForUpdateTime + m_cfg.CheckForUpdateInterval * DAY) 
		return;

    Thread().Create(new CheckForUpdateThread());

	m_cfg.LastCheckForUpdateTime = current_time;
}

void CNavigatorSupervisor::onimportrules(WEBBrowser browser, CString strURL, DISPID dispIdMember, LPVARIANT pResult)
{
	HTML::Event event = browser.event;

    CComPtr<IWindowManager> pManager;
    if (FAILED(pManager.CoCreateInstance(L"XPCOMAdapter.WindowManager.1")))
        return;

    pManager->openDialog(CComBSTR(L"res://{8706081B-A7C0-4EC6-BDFF-A6F54B24A837}/ImportRules.htm"), 800, 500, CComVariant(strURL), CComVariant(), CComVariant(), CComVariant(), CComVariant(), CComVariant(), CComVariant(), CComVariant(), CComVariant(), CComVariant());
    
	event.returnValue = false;
}

void CNavigatorSupervisor::onclickdirectlink(WEBBrowser browser, CString strURL, DISPID dispIdMember, LPVARIANT pResult)
{
	HTML::Event event = browser.event;

    if (!m_cfg.fullscreenImageLink)
        return;

    CComPtr<IWindowManager> pManager;
    if (FAILED(pManager.CoCreateInstance(L"XPCOMAdapter.WindowManager.1")))
        return;

    pManager->openHiddenDialog(CComBSTR(L"res://{8706081B-A7C0-4EC6-BDFF-A6F54B24A837}/CONTEXT-MENU-FULLSCREEN.HTM"), CComVariant(strURL), CComVariant(browser.document.location.href), CComVariant(), CComVariant(), CComVariant(), CComVariant(), CComVariant(), CComVariant(), CComVariant(), CComVariant());
    
	event.returnValue = false;
}

void CNavigatorSupervisor::onstartslideshow(WEBBrowser browser, DISPID dispIdMember, LPVARIANT pResult)
{
    StartSlideShow(browser.document);
}

STDMETHODIMP CNavigatorSupervisor::DocumentComplete(IDispatch* pDisp, VARIANT* URL)
{
#ifdef _DEBUG
		if (URL && (URL->vt & VT_BSTR) && URL->bstrVal)
			ATLTRACE( _T("CNavigatorSupervisor::DocumentComplete %s\n"), CString(URL->bstrVal) );
		else
			ATLTRACE( _T("CNavigatorSupervisor::DocumentComplete - Cannot read location\n") );
#endif

    if (!pDisp)
		return S_OK;

    CString strURL;
    if (URL && (URL->vt & VT_BSTR) && URL->bstrVal)
        strURL = URL->bstrVal;

    if ( 0 == _tcsnicmp(strURL, _T("http://"), 7) )
    {
        WEBBrowser browser(pDisp);
        if (!browser || !browser.document || !browser.document.body)
            return S_OK;

        if (strURL.Find( _T("webslideshow-autostart") ) != -1) // run slide show
            StartSlideShow(browser.document);

        SearchMagicElements(browser);

        RulesUpdateManager::CheckForPredefinedRulesUpdate();

        CheckForUpdate();
    }
    else if ( 0 == _tcsnicmp(strURL, m_strResPath, m_strResPath.GetLength()) )
    { // page from this DLL
        CWindow wnd = m_browser.wnd;
        if (wnd)
        {
            CIconHandle icoLogo;
            if (icoLogo.LoadIcon(IDI_LOGO, 32, 32))
                wnd.SetIcon(icoLogo);

            CIconHandle icoSmallLogo;
            if (icoSmallLogo.LoadIcon(IDI_LOGO, 16, 16))
                wnd.SetIcon(icoSmallLogo, FALSE);
        }
    }

	return S_OK;
}

void CNavigatorSupervisor::StartSlideShow(const HTML::Document& doc)
{
    CComPtr<IWindowManager> pManager;
    if (FAILED(pManager.CoCreateInstance(L"XPCOMAdapter.WindowManager.1")))
        return;

    pManager->openHiddenDialog(CComBSTR(L"res://{8706081B-A7C0-4EC6-BDFF-A6F54B24A837}/CONTEXT-MENU-SLIDESHOW.HTM"), CComVariant(doc), CComVariant(doc.location.href), CComVariant(), CComVariant(), CComVariant(), CComVariant(), CComVariant(), CComVariant(), CComVariant(), CComVariant());
}

bool CNavigatorSupervisor::IsDirectLink(LPOLESTR pszURL)
{
    if (!pszURL || !*pszURL || wcschr(pszURL, L'?'))
        return false;

    CString strExt = ExtractFileExtension(pszURL);
    return !strExt.IsEmpty() && NULL != wcsstr(L"jpg|jpeg|png|bmp|tif|tiff", strExt);
}

void CNavigatorSupervisor::SearchMagicElements(const WEBBrowser& browser)
{
    HTML::Collection<> all = browser.document.all;
	if (!all.length) // empty document
		return;

    for(HTML::Collection<HTML::AnchorElement>::Iterator it(all.tags[L"a"]); (bool)it; ++it)
    {
        if ((*it).className == L"webslideshow-start")
        {
            (*it).onclick = CHtmlEvent<CNavigatorSupervisor, WEBBrowser>::CreateHandler(this, &CNavigatorSupervisor::onstartslideshow, browser);
            (*it).href = L"javascript: void(0);";
        }
        else if ((*it).className == L"webslideshow-rules")
        {
            (*it).onclick = CHtmlEvent2<CNavigatorSupervisor, WEBBrowser, CString>::CreateHandler(this, &CNavigatorSupervisor::onimportrules, browser, (CStringW)(*it).href);
            (*it).href = L"javascript: void(0);";
        }
        else if (IsDirectLink((*it).href) && !(*it).onclick)
        {
            (*it).onclick = CHtmlEvent2<CNavigatorSupervisor, WEBBrowser, CString>::CreateHandler(this, &CNavigatorSupervisor::onclickdirectlink, browser, (CStringW)(*it).href);
        }
    }

    for(HTML::Collection<>::Iterator it(all.tags[L"input"]); (bool)it; ++it)
    {
        if ((*it).IsButton() && (*it).className == L"webslideshow-start")
        {
            (*it).onclick = CHtmlEvent<CNavigatorSupervisor, WEBBrowser>::CreateHandler(this, &CNavigatorSupervisor::onstartslideshow, browser);
        }
    }

    for(HTML::Collection<>::Iterator it(all.tags[L"button"]); (bool)it; ++it)
    {
        if ((*it).IsButton() && (*it).className == L"webslideshow-start")
        {
            (*it).onclick = CHtmlEvent<CNavigatorSupervisor, WEBBrowser>::CreateHandler(this, &CNavigatorSupervisor::onstartslideshow, browser);
        }
    }

    if (m_cfg.useSubscriptions)
    {
        HTML::InputHiddenElement subscription(browser.document.getElementById("WebSlideShow-Subscription"));
        if (subscription) RulesUpdateManager::CheckForSubscriptionUpdate(subscription.value);
    }
}
